#include "enumeration.h"

#include "bool.h"

#include <QtCore/QVariant>

using namespace core;

const TypeName Enumeration::NAME = Type::demangledName(
    typeid(Enumeration).name());
const TypeValue Enumeration::INVALID = "EInvalid";

Enumeration::Enumeration() : ValueType(),
    m_name(),
    m_value(INVALID),
    m_values()
{

}

Enumeration::Enumeration(const EnumerationName& name,
    const QSet<QString> &values) : ValueType(),
        m_name(name),
        m_value(INVALID),
        m_values(values)
{
    m_values.insert(INVALID);

    m_operations.insert(OPERATION_EQUALTO, OP(Bool::NAME));
    m_operations.insert(OPERATION_NEQUALTO, OP(Bool::NAME));
}

Enumeration::Enumeration(const Enumeration& other) : ValueType(),
    m_name(other.m_name),
    m_value(other.m_value),
    m_values(other.m_values)
{

}

Enumeration::~Enumeration()
{

}

QString Enumeration::name() const
{
    Q_ASSERT(!m_name.isEmpty());

    return m_name;
}

bool Enumeration::matches(const TypeName& name) const
{
    Q_ASSERT(!m_name.isEmpty());

    return m_name == name || NAME == name;
}

bool Enumeration::matches(const Type& type) const
{
    Q_ASSERT(!m_name.isEmpty());

    const Enumeration* other = dynamic_cast<const Enumeration* >(&type);
    return other != 0 ? m_name == other->m_name : false;
}

void Enumeration::setValue(const QVariant& value)
{
    Q_ASSERT(!m_name.isEmpty());

    if (value.canConvert(QVariant::String))
    {
        const QString val = value.toString().remove("$");
        m_value = m_values.contains(val) ? val : INVALID;
    }
}

QVariant Enumeration::getValue() const
{
    Q_ASSERT(!m_name.isEmpty());

    return QVariant(m_value);
}

bool Enumeration::operator ==(const Type& type) const
{
    Q_ASSERT(!m_name.isEmpty());

    const Enumeration* other = dynamic_cast<const Enumeration *>(&type);
    return other != 0 ? (m_name == other->m_name &&
        m_values == other->m_values &&
        m_value == other->m_value) : false;
}

bool Enumeration::operator !=(const Type& type) const
{
    Q_ASSERT(!m_name.isEmpty());

    const Enumeration* other = dynamic_cast<const Enumeration *>(&type);
    return other != 0 ? (m_name != other->m_name ||
        m_values != other->m_values ||
        m_value != other->m_value) : true;
}

bool Enumeration::canConvert(const TypeValue& value) const
{
    Q_ASSERT(!m_name.isEmpty());

    TypeValue _value = value;

    return m_values.contains(_value.remove("$"));
}

ValueKeywordMask Enumeration::keywordMask() const
{
    Q_ASSERT(!m_name.isEmpty());

    return "\\$\\w*\\$";
}

bool Enumeration::hasIdentity() const
{
    Q_ASSERT(!m_name.isEmpty());

    return true;
}

void Enumeration::setIdentity(const Type& identity)
{
    const Enumeration* other = dynamic_cast<const Enumeration* >(&identity);

    if (other != 0 && m_name.isEmpty() && m_values.isEmpty())
    {
        m_name = other->m_name;
        m_values = other->m_values;
    }
}

Type* Enumeration::copy() const
{
    Q_ASSERT(!m_name.isEmpty());

    Enumeration* newInstance = new Enumeration(*this);
    return newInstance;
}
